package club.baimahu.pencil.servlet.annotation;

import club.baimahu.pencil.servlet.Handler;
import club.baimahu.pencil.servlet.SimpleHandler;
import club.baimahu.pencil.servlet.SimpleHandlerFactory;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLDecoder;
import java.util.*;

public class AnnotationScanner {

    Set<Class> controllers = null;

    Set<Class> classes = null;

    static Map<String,Map<String, Handler>> maps = null;


    public static Set<Class> getControllers(String packagePath){
        Set<Class>  classes = getClassesBySpring(packagePath);
        Set<Class> ctlClasses = new HashSet<>();
        for(Class clazz : classes){
            if(clazz.getAnnotation(Controller.class) != null){
                ctlClasses.add(clazz);
            }
        }
        return ctlClasses;
    }

    public static Map<String,Map<String,Handler>> getHandler(String packagePath){
        if(maps == null){
            synchronized (AnnotationScanner.class){
                if(maps == null){
                    maps = new HashMap();
                    Set<Class> ctlClasses = getControllers(packagePath);
                    for(Class clazz : ctlClasses){
                        Method[] methods = clazz.getDeclaredMethods();
                        for(Method method : methods){
                            RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
                            if(requestMapping != null){
                                String uri = requestMapping.value();
                                String[] requestMethods = requestMapping.methods();
                                if(!uri.startsWith("/")){
                                    uri = "/" + uri ;
                                }
                                if(requestMethods == null){

                                }
                                SimpleHandler simpleHandler = SimpleHandlerFactory.getSimpleHandler(method);
                                for(String requestMethod : requestMethods){
                                    Map<String,Handler> m = maps.get(uri);
                                    if(m == null){
                                        m = new HashMap();
                                        maps.put(uri,m);
                                    }
                                    m.put(requestMethod.toUpperCase(),simpleHandler);
                                }
                            }
                        }
                    }
                }
            }
        }

        return maps;
    }

    public static Set<Class> getClasses(String packagePath){

        Set<Class> classes = new HashSet<>();

        boolean recursive = true;

        String packDirName = packagePath.replace(".","/");

        Enumeration<URL> dirs;

        try{
            dirs = Thread.currentThread().getContextClassLoader().getResources(packDirName);
            while(dirs.hasMoreElements()){
                URL url = dirs.nextElement();
                String protocol = url.getProtocol();
                if(protocol.equals("file")){
                    String filePath = URLDecoder.decode(url.getFile(),"utf-8");

                }

            }

        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }


    public static Set<Class> getClassesBySpring(String packageName) {
        if(packageName == null){
            throw new IllegalArgumentException("packageName can not be null");
        }
        packageName = packageName.replace(".","/");

        List<Class<?>> classList = new ArrayList<Class<?>>();
        {
            try {

                ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
                MetadataReaderFactory metaReader = new CachingMetadataReaderFactory();
                Resource[] resources = resolver.getResources("classpath*:"+packageName+"/**/*.class");
                ClassLoader loader = ClassLoader.getSystemClassLoader();
                for (Resource resource : resources) {
                    MetadataReader reader = null;
                    reader = metaReader.getMetadataReader(resource);
                    String className = reader.getClassMetadata().getClassName();
                    Class<?> clazz = loader.loadClass(className);
                    classList.add(clazz);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return new HashSet<>(classList);
    }

    public void addClasses(String packageName,String packagePath,boolean isRecursive ,Set<Class> classes){
        File file = new File(packagePath);
        if(!file.exists() || !file.isDirectory()){
            return;
        }
        File[] subFiles = file.listFiles(new FileFilter() {
            @Override
            public boolean accept(File file) {
                return file.getName().endsWith(".class") || file.isDirectory();
            }
        });
        for(File subFile : subFiles){

        }

    }
}
